<template>
  <div>
    <van-uploader
      v-model="fileList"
      :accept="accept"
      :result-type="resultType"
      :maxSize="maxSizeFn"
      @oversize="onOversize"
      :afterRead="afterReadFn"
      :before-read="beforeReadFn"
      :before-delete="beforeDeleteFn"
      v-bind="attrs"
      v-on="events"
      class="upload"
    >
      <template #preview-cover="{ file,fileName }">
        <div
          class="preview-cover van-ellipsis"
          v-if="fileName|| file && file.name"
        >{{fileName|| file && file.name ||'' }}</div>
      </template>
    </van-uploader>
  </div>
</template>

<script>

// import {  isImageFile as isImageFileFn } from 'vant/lib/index'; // Mixins
const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i;
function isImageUrl(url) {
  return IMAGE_REGEXP.test(url);
}
function isImageFileFn(item) {
  // some special urls cannot be recognized
  // user can add `isImage` flag to mark it as an image url
  if (item.isImage) {
    return true;
  }

  if (item.file && item.file.type) {
    return item.file.type.indexOf('image') === 0;
  }

  if (item.url) {
    return isImageUrl(item.url);
  }

  if (item.content) {
    return item.content.indexOf('data:image') === 0;
  }

  return false;
}

import { mimeType } from './mimeType'
import { Vant } from '@components/Vant/index'
const mimeTypeMap = new Map();
mimeType.forEach(cur => {
  mimeTypeMap.set(cur.type, cur.ext)
  mimeTypeMap.set(cur.ext, cur.ext)
});

// import Compressor from 'compressorjs';
import { upload, getImg, deleteFile } from '@apis/upload'
export default {
  props: {
    value: {
      type: [String],
      default() {
        return ''
      }
    },
    maxSize: {
      type: [Number, String, Function]
    },
    beforeRead: {
      type: Function
    },
    afterRead: {
      type: Function
    },
    accept: {
      type: String
    },
    resultType: {
      type: String,
      default: 'file' // 默认追加了url
    },
  },
  data() {
    return {
      fileList: [],
      // fileList: [
      //   { url: 'https://img01.yzcdn.cn/vant/leaf.jpg' },
      //   // Uploader 根据文件后缀来判断是否为图片文件
      //   // 如果图片 URL 中不包含类型信息，可以添加 isImage 标记来声明
      //   // { url: 'https://cloud-image', isImage: true },
      // ],
    }
  },
  watch: {
    value: {
      immediate: true,
      handler(v) {
        if (v) {
          const keys = v.split(',');
          // 预览添加key,创建url
          keys.forEach((key) => {

            const index = this.fileList.findIndex(item => item && item._key === key)
            if (index === -1) {
              this.fileList.push({
                _key: key,

                status: 'uploading',
                message: '加载中...'
              });
              const i = this.fileList.findIndex(item => item && item._key === key)
              const item = this.fileList[i];
              this.getImg({ key }).then(({ url, name = '', type = '' } = {}) => {
                url && this.$set(item, 'isImage', type.includes('image'));
                url && this.$set(item, 'url', url);
                name && this.$set(item, 'fileName', name);
                this.setStatus(item, 'done', '加载完成');
                this.revokeObjectURL(url);
              }).catch((e) => {
                console.log(JSON.stringify(e));
                this.setStatus(item, 'failed', '加载失败')
              })
            }
          })
        }
      }
    },
    fileList: {
      deep: true,
      handler(v) {
        v.forEach(item => {
          const { url, file } = item
          var isImageFile = isImageFileFn(item);

          if (!url && isImageFile && file) {
            const url = window.URL.createObjectURL(file)
            this.$set(item, 'url', url)
            this.revokeObjectURL(url);
          }
        })
        this.$emit('input', v.map(item => item._key).filter(Boolean).join(','))
      }
    }
  },
  mounted() {
    // console.log(Compressor);

  },
  computed: {
    attrs() {
      let attrs = Object.assign({}, this.$attrs || {})
      return attrs
    },
    events() {
      let events = Object.assign({}, this.$listeners || {})
      delete events.input
      return events
    }
  },
  methods: {
    revokeObjectURL(/* url */) {
      /* this.$nextTick(() => {
        this.$nextTick(() => {
          window.URL.revokeObjectURL(url);
        })
      }) */
    },
    getImg(key) {
      return getImg(key).then(res => {
        const { type, url, name } = res || {}
        return {
          type, url, name
        }
      })
    },
    getExt(s) {
      s && (s = s.replace(/^\s+|\s+$/g, ''))
      return mimeTypeMap.get(s) || s
    },
    beforeReadFn(file) {
      if (this.accept) {
        let accepts = this.accept.split(',').map(this.getExt) || [];
        accepts = [...(new Set(accepts))];
        const { type } = file;

        if (!type || !accepts.includes(this.getExt(type))) {
          Vant.Toast(`请上传${accepts.join('、')}格式文件`);
          return false;
        } else {
          return this.beforeRead ? this.beforeRead(...arguments) : true;
        }
      } else {
        return this.beforeRead ? this.beforeRead(...arguments) : true;
      }
    },
    maxSizeFn(file) {
      const { type, size } = file;

      let max = 0;
      const { maxSize } = this

      if (maxSize) {
        if (typeof maxSize === 'function') {
          return maxSize(...arguments);
        } else {
          max = maxSize
        }
      } else if (type.startsWith('image')) {
        // max = 1024 * 1024
      } else {
        // max = 1024 * 1024 * 2
      }

      return max ? size >= max : false;
    },
    onOversize({ file }) {
      const { $attrs = {}, maxSize = '' } = this;
      const max = $attrs['max-size'] || maxSize || ''
      max && Vant.Toast(`文件大小超过限制${max ? this.b2k(max) + 'kb,该文件大小为' + this.b2k(file.size) + 'kb' : ''}`);
      this.$emit('onOversize', ...arguments)
    },
    b2k(n) {
      return parseInt(n / 1024)
    },
    afterReadFn(file) {
      // 此时可以自行将文件上传至服务器
      this.setStatus(file, 'uploading', '上传中...')

      this.uploadAxios(file).then((...arg) => {
        this.setStatus(file, 'done', '上传成功')
        this.afterRead && this.afterRead(...arg);


      }).catch(() => {
        const index = this.fileList.find(item => item === file);
        index !== -1 && this.fileList.splice(index, 1);
        file.status = 'failed';
        file.message = '上传失败';
      })
    },
    getKeys() {
      return this.fileList.map(item => item.key).join(',')
    },
    uploadAxios(item = {}) {
      const { file } = item
      let data = new FormData()       // 创建form对象     
      data.append('file', file)       // 通过append向form对象添加数据
      // data.append("需要接受的数据名", "数据"); // 添加form表单中其他数据
      let config = {
        headers: { 'Content-Type': 'multipart/form-data' }
      }
      return upload(data, config).then(res => {
        const { data: key = '' } = res || {}
        item._key = key
        return key
      })
    },
    setStatus(keyOrFile, status, message) {
      let item;
      if (typeof keyOrFile === 'string') {
        const i = this.fileList.findIndex(item => item && item._key === keyOrFile);
        if (i === -1) {
          return;
        }
        item = this.fileList[i]
      } else if (typeof keyOrFile === 'object') {
        item = keyOrFile
      }

      this.$set(item, 'status', status)
      this.$set(item, 'message', message)
    },
    beforeDeleteFn(item = {}) {
      this.setStatus(item, 'uploading', '删除中...')
      /* const p = new Promise((resolve) => {
        setTimeout(() => {
          
          resolve()
        }, 1000)
      }) */
      return deleteFile({ keys: [item._key] }).then(() => {
        this.setStatus(item, 'done', '删除成功')
      }).catch(()=>{
        this.setStatus(item, 'done', '删除失败')
        return Promise.reject()
      })
    }
  }
}
</script>

<style lang="less" scoped>
.preview-cover {
  position: absolute;
  bottom: 0;
  box-sizing: border-box;
  width: 100%;
  padding: 4px;
  color: #fff;
  font-size: 12px;
  line-height: 16px;
  text-align: center;
  background: rgba(0, 0, 0, 0.3);
}
.upload {
  & /deep/ .van-uploader__file-name.van-ellipsis {
    display: none;
  }
}
</style>